package com.lap.framework.common.dto.page;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

/**
 * 分页返回结果,创建方式参考 {@link PageResponse#ok(Long)}
 *
 * @author Shuisheng Lao(劳水生)
 * @version 1.0.0
 */
@Getter
@ToString
@EqualsAndHashCode
@Schema(description = "分页结果信息")
public class PageResponse<T> {

  @Schema(description = "数据对象")
  private final List<T> rows;

  @Schema(description = "总记录数")
  private final Long totalItem;

  private PageResponse(Long totalItem) {
    this(null, totalItem);
  }

  private PageResponse(List<T> data, Long totalItem) {
    this.rows = data;
    this.totalItem = totalItem;
  }

  /**
   * 将当前分页响应中的数据转换为另一种类型
   *
   * @param <R> 目标数据类型
   * @param convert 数据转换函数，用于将原数据类型 T 转换为目标类型 R
   * @return 包含转换后数据的新 PageResponse 对象，保留原始的总条目数
   * @apiNote 示例用法：
   * <pre>
   * {@code
   * PageResponse<Integer> intResponse = ...;
   * // 将 Integer 转换为 String
   * PageResponse<String> strResponse = intResponse.map(Object::toString);
   * }
   * </pre>
   *
   * <pre>
   * @implSpec
   * 1. 如果原始数据(rows)为 null，转换后的数据也将保持为 null
   * 2. 原始的总条目数(totalItem)会被保留到新对象中
   * 3. 转换过程使用 Java Stream API，保证线程安全
   * </pre>
   * @throws NullPointerException 如果 convert 参数为 null
   */
  public <R> PageResponse<R> map(Function<T, R> convert) {
    Objects.requireNonNull(convert, "转换函数不能为null");

    List<R> dataList =
        (this.rows == null)
            ? null
            : this.rows.stream() // 将原始列表转为流
                .map(convert) // 应用转换函数
                .toList(); // 收集为不可变列表

    return new PageResponse<>(dataList, totalItem);
  }

  /**
   * 创建一个分页传输对象
   *
   * @param totalItem 总记录
   * @param <R> 对象类型
   * @return 分页传输对象
   */
  public static <R> PageResponse<R> ok(Long totalItem) {
    return new PageResponse<>(totalItem);
  }

  /**
   * 创建一个分页返回传输对象
   *
   * @param data 分页数据
   * @param totalItem 总记录
   * @param <R> 对象类型
   * @return 分页传输对象
   */
  public static <R> PageResponse<R> ok(List<R> data, Long totalItem) {
    return new PageResponse<>(data, totalItem);
  }
}
